/*
 * Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
 *
 * This file is part of Loop Habit Tracker.
 *
 * Loop Habit Tracker is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * Loop Habit Tracker is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package org.isoron.uhabits.activities;

import android.content.*;
import android.os.*;
import android.support.annotation.*;
import android.view.*;

import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;

import java.io.*;
import java.lang.Process;
import java.util.*;

import javax.inject.*;

/**
 * Base class for all systems class in the application.
 * <p>
 * Classes derived from BaseSystem are responsible for handling events and
 * sending requests to the Android operating system. Examples include capturing
 * a bug report, obtaining device information, or requesting runtime
 * permissions.
 */
@ActivityScope
public class BaseSystem
{
    private Context context;

    @Inject
    public BaseSystem(@ActivityContext Context context)
    {
        this.context = context;
    }

    /**
     * Captures a bug report and saves it to a file in the SD card.
     * <p>
     * The contents of the file are generated by the method {@link
     * #getBugReport()}. The file is saved in the apps's external private
     * storage.
     *
     * @return the generated file.
     * @throws IOException when I/O errors occur.
     */
    @NonNull
    public File dumpBugReportToFile() throws IOException
    {
        String date =
            DateFormats.getBackupDateFormat().format(DateUtils.getLocalTime());

        if (context == null) throw new RuntimeException(
            "application context should not be null");
        File dir = FileUtils.getFilesDir(context, "Logs");
        if (dir == null) throw new IOException("log dir should not be null");

        File logFile =
            new File(String.format("%s/Log %s.txt", dir.getPath(), date));
        FileWriter output = new FileWriter(logFile);
        output.write(getBugReport());
        output.close();

        return logFile;
    }

    /**
     * Captures and returns a bug report.
     * <p>
     * The bug report contains some device information and the logcat.
     *
     * @return a String containing the bug report.
     * @throws IOException when any I/O error occur.
     */
    @NonNull
    public String getBugReport() throws IOException
    {
        String logcat = getLogcat();
        String deviceInfo = getDeviceInfo();

        String log = "---------- BUG REPORT BEGINS ----------\n";
        log += deviceInfo + "\n" + logcat;
        log += "---------- BUG REPORT ENDS ------------\n";

        return log;
    }

    public String getLogcat() throws IOException
    {
        int maxLineCount = 250;
        StringBuilder builder = new StringBuilder();

        String[] command = new String[]{ "logcat", "-d" };
        Process process = Runtime.getRuntime().exec(command);

        InputStreamReader in = new InputStreamReader(process.getInputStream());
        BufferedReader bufferedReader = new BufferedReader(in);

        LinkedList<String> log = new LinkedList<>();

        String line;
        while ((line = bufferedReader.readLine()) != null)
        {
            log.addLast(line);
            if (log.size() > maxLineCount) log.removeFirst();
        }

        for (String l : log)
        {
            builder.append(l);
            builder.append('\n');
        }

        return builder.toString();
    }

    private String getDeviceInfo()
    {
        if (context == null) return "null context\n";

        WindowManager wm =
            (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        return
            String.format("App Version Name: %s\n", BuildConfig.VERSION_NAME) +
            String.format("App Version Code: %s\n", BuildConfig.VERSION_CODE) +
            String.format("OS Version: %s (%s)\n",
                System.getProperty("os.version"), Build.VERSION.INCREMENTAL) +
            String.format("OS API Level: %s\n", Build.VERSION.SDK) +
            String.format("Device: %s\n", Build.DEVICE) +
            String.format("Model (Product): %s (%s)\n", Build.MODEL,
                Build.PRODUCT) +
            String.format("Manufacturer: %s\n", Build.MANUFACTURER) +
            String.format("Other tags: %s\n", Build.TAGS) +
            String.format("Screen Width: %s\n",
                wm.getDefaultDisplay().getWidth()) +
            String.format("Screen Height: %s\n",
                wm.getDefaultDisplay().getHeight()) +
            String.format("External storage state: %s\n\n",
                Environment.getExternalStorageState());
    }
}
